#pragma once

template <typename... Arg>
class Delegate
{

public:
    virtual void operator()(Arg... arg) const = 0;

};

template <class TObject, typename TRet, typename... Arg>
class MethodDelegate : public Delegate<Arg...>
{

public:
    MethodDelegate(TObject* object, TRet (TObject::*method)(Arg...)) :
         _object(object), _method(method)
    {}

    void operator()(Arg... arg) const
    {
        (_object->*_method)(arg...);
     }

private:
    TObject* _object;
    TRet (TObject::*_method)(Arg...);

};

template <class TObject, typename TRet, typename... Arg>
class ConstMethodDelegate : public Delegate<Arg...>
{

public:
    ConstMethodDelegate(const TObject* object, TRet (TObject::*method)(Arg...) const) :
        _object(object), _method(method)
    {}

    void operator()(Arg... arg) const
    {
        (_object->*_method)(arg...);
    }

private:
    const TObject* _object;
    TRet (TObject::*_method)(Arg...) const;

};

template <typename TRet, typename... Arg>
class FunctionDelegate : public Delegate<Arg...>
{

public:
    FunctionDelegate(TRet (*function)(Arg...)) :
         _function(function)
    {}

    void operator()(Arg... arg) const
    {
        (*_function)(arg...);
     }

private:
    TRet (*_function)(Arg...);

};
